package com.ssy.lingxi.member.merchant.serviceimpl.paas;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.member.MemberConfigTagEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MemberConfigLabelQueryVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MemberConfigQueryVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MemberConfigVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MemberRuleFeignVO;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.constant.MemberConfigStatusEnum;
import com.ssy.lingxi.member.merchant.repository.*;
import com.ssy.lingxi.member.merchant.service.paas.IPaasMemberConfigService;
import com.ssy.lingxi.member.merchant.utils.MemberConfigLabelUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 会员注册资料配置接口实现
 * @author 万宁
 * @date 2020-05-29
 * @version 2.0.0
 */
@Service
public class PaasMemberConfigServiceImpl implements IPaasMemberConfigService {
    @Resource
    private MemberConfigRepository memberConfigRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private MemberConfigLabelRepository memberConfigLabelRepository;

    @Resource
    private MemberRegisterDetailRepository memberRegisterDetailRepository;

    @Resource
    private MemberDepositoryDetailRepository memberDepositoryDetailRepository;

    @Resource
    private BaseMemberRuleRepository baseMemberRuleRepository;

    /**
     * 新增注册资料配置
     * @param configVO 接口参数
     * @return 新增结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<MemberConfigQueryVO> addMemberConfig(MemberConfigVO configVO) {
        //查找字段名称是否已经存在
        if(memberConfigRepository.existsByFieldNameOrFieldLocalName(configVO.getFieldName(), configVO.getFieldLocalName())) {
            return Wrapper.fail(ResponseCode.MC_MS_FIELD_NAME_EXISTS);
        }

        if(configVO.getTagEnum() == null) {
            configVO.setTagEnum(0);
        }

        if(!configVO.getTagEnum().equals(0)) {
            if(!MemberConfigTagEnum.isEnumCode(configVO.getTagEnum())) {
                return Wrapper.fail(ResponseCode.REQUEST_PARAM_CHECK_FAILED, "字段标签枚举不在定义范围内");
            }

            if(memberConfigRepository.existsByTagEnum(configVO.getTagEnum())) {
                return Wrapper.fail(ResponseCode.REQUEST_PARAM_CHECK_FAILED, "字段标签：" + MemberConfigTagEnum.findTagName(configVO.getTagEnum()) + " 已经定义");
            }
        }

        MemberConfigDO memberConfigDO = new MemberConfigDO();
        memberConfigDO.setFieldName(configVO.getFieldName().trim());
        memberConfigDO.setFieldLocalName(configVO.getFieldLocalName().trim());
        memberConfigDO.setFieldType(configVO.getFieldType().trim());
        memberConfigDO.setAttr(configVO.getAttr());
        memberConfigDO.setFieldLength(configVO.getFieldLength());
        memberConfigDO.setFieldEmpty(configVO.getFieldEmpty());
        memberConfigDO.setGroupName(configVO.getGroupName().trim());
        memberConfigDO.setFieldOrder(configVO.getFieldOrder());
        //新增时默认为启用状态
        memberConfigDO.setFieldStatus(MemberConfigStatusEnum.ENABLED.getCode());
        memberConfigDO.setFieldRemark(StringUtils.hasLength(configVO.getFieldRemark()) ? configVO.getFieldRemark().trim() : "");
        memberConfigDO.setTagEnum(configVO.getTagEnum());
        memberConfigDO.setTagName(MemberConfigTagEnum.findTagName(configVO.getTagEnum()));
        memberConfigDO.setValidate(configVO.getValidate());
        memberConfigDO.setRuleEnum(configVO.getRuleEnum());

        List<MemberConfigLabelDO> items = CollectionUtils.isEmpty(configVO.getFieldEnum()) ? new ArrayList<>() : configVO.getFieldEnum().stream().map(item -> {
            MemberConfigLabelDO itemDO = new MemberConfigLabelDO();
            itemDO.setLabelValue(item.getLabel());
            itemDO.setLabelOrder(item.getOrder());
            return itemDO;
        }).collect(Collectors.toList());

        //一对多双向关联，并且CascadeType=DETACH的时候，其中一方要先保存，再设置关联，再更新
        memberConfigLabelRepository.saveAll(items);

        memberConfigDO.setLabels(new HashSet<>(items));

        memberConfigRepository.saveAndFlush(memberConfigDO);

        items.forEach(item -> item.setMemberConfig(memberConfigDO));

        memberConfigLabelRepository.saveAll(items);

        MemberConfigQueryVO queryVO = new MemberConfigQueryVO();
        queryVO.setId(memberConfigDO.getId());
        queryVO.setFieldName(memberConfigDO.getFieldName());
        queryVO.setFieldLocalName(memberConfigDO.getFieldLocalName());
        queryVO.setFieldType(memberConfigDO.getFieldType());
        queryVO.setAttr(memberConfigDO.getAttr());
        queryVO.setFieldLength(memberConfigDO.getFieldLength());
        queryVO.setFieldEmpty(memberConfigDO.getFieldEmpty());
        queryVO.setFieldOrder(memberConfigDO.getFieldOrder());
        queryVO.setGroupName(memberConfigDO.getGroupName());
        queryVO.setFieldRemark(memberConfigDO.getFieldRemark());
        queryVO.setTagEnum(memberConfigDO.getTagEnum());
        queryVO.setFieldStatus(memberConfigDO.getFieldStatus());
        queryVO.setValidate(memberConfigDO.getValidate());
        queryVO.setFieldEnum(CollectionUtils.isEmpty(memberConfigDO.getLabels()) ? new ArrayList<>() : memberConfigDO.getLabels().stream().map(item -> {
            MemberConfigLabelQueryVO itemQueryVO = new MemberConfigLabelQueryVO();
            itemQueryVO.setId(item.getId());
            itemQueryVO.setLabel(item.getLabelValue());
            itemQueryVO.setOrder(item.getLabelOrder());
            return itemQueryVO;
        }).collect(Collectors.toList()));

        return Wrapper.success(queryVO);
    }

    /**
     * 更新注册资料配置
     * @param configVO 接口参数
     * @return 更新结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<MemberConfigQueryVO> updateMemberConfig(MemberConfigVO configVO) {
        //检查会员资料配置是否存在
        MemberConfigDO memberConfigDO = memberConfigRepository.findById(configVO.getId()).orElse(null);
        if(memberConfigDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_DETAIL_DOES_NOT_EXIST);
        }

        //检查是否已经存在字段名称相同，id不同的记录
        if(memberConfigRepository.countByFieldNameOrFieldLocalNameNotEqId(configVO.getFieldName(),configVO.getFieldLocalName(),configVO.getId()) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_FIELD_NAME_EXISTS);
        }

        if(configVO.getTagEnum() == null) {
            configVO.setTagEnum(0);
        }

        if(configVO.getRuleEnum() == null) {
            configVO.setRuleEnum(0);
        }

        if(!configVO.getTagEnum().equals(0)) {
            if(!MemberConfigTagEnum.isEnumCode(configVO.getTagEnum())) {
                return Wrapper.fail(ResponseCode.REQUEST_PARAM_CHECK_FAILED, "字段标签枚举不在定义范围内");
            }

            if(memberConfigRepository.existsByTagEnumAndIdNot(configVO.getTagEnum(), memberConfigDO.getId())) {
                return Wrapper.fail(ResponseCode.REQUEST_PARAM_CHECK_FAILED, "字段标签：" + MemberConfigTagEnum.findTagName(configVO.getTagEnum()) + " 已经定义");
            }
        }

        //更改状态、设置规则有另外一个接口，所以在此排除这两个字段，不做更新
        memberConfigDO.setFieldName(configVO.getFieldName());
        memberConfigDO.setFieldLocalName(configVO.getFieldLocalName());
        memberConfigDO.setFieldType(configVO.getFieldType());
        memberConfigDO.setAttr(configVO.getAttr());
        memberConfigDO.setFieldLength(configVO.getFieldLength());
        memberConfigDO.setFieldEmpty(configVO.getFieldEmpty());
        memberConfigDO.setGroupName(configVO.getGroupName());
        memberConfigDO.setFieldOrder(configVO.getFieldOrder());
        memberConfigDO.setFieldRemark(StringUtils.hasLength(configVO.getFieldRemark()) ? configVO.getFieldRemark() : "");
        memberConfigDO.setTagEnum(configVO.getTagEnum());
        memberConfigDO.setTagName(MemberConfigTagEnum.findTagName(configVO.getTagEnum()));
        memberConfigDO.setRuleEnum(configVO.getRuleEnum());
        memberConfigDO.setValidate(configVO.getValidate());
        //PaaS层修改信息后，会自动将状态设置为“有效”
        memberConfigDO.setFieldStatus(EnableDisableStatus.ENABLE.getCode());

        //删除后新增标签枚举
        memberConfigLabelRepository.deleteAll(memberConfigDO.getLabels());

        List<MemberConfigLabelDO> items = CollectionUtils.isEmpty(configVO.getFieldEnum()) ? new ArrayList<>() : configVO.getFieldEnum().stream().map(item -> {
            MemberConfigLabelDO itemDO = new MemberConfigLabelDO();
            itemDO.setLabelValue(item.getLabel());
            itemDO.setLabelOrder(item.getOrder());
            return itemDO;
        }).collect(Collectors.toList());

        //一对多双向关联，并且CascadeType=DETACH的时候，其中一方要先保存，再设置关联，再更新
        memberConfigLabelRepository.saveAll(items);

        memberConfigDO.setLabels(new HashSet<>(items));

        memberConfigRepository.saveAndFlush(memberConfigDO);

        items.forEach(item -> item.setMemberConfig(memberConfigDO));

        memberConfigLabelRepository.saveAll(items);

        //更新所有会员注册资料配置
        List<MemberRegisterDetailDO> registerDetails = memberRegisterDetailRepository.findByMemberConfig(memberConfigDO);
        if(!CollectionUtils.isEmpty(registerDetails)) {
            registerDetails.forEach(registerDetail -> {
                registerDetail.setFieldName(memberConfigDO.getFieldName());
                registerDetail.setFieldLocalName(memberConfigDO.getFieldLocalName());
                registerDetail.setFieldType(memberConfigDO.getFieldType());
                registerDetail.setAttr(memberConfigDO.getAttr());
                registerDetail.setValidate(memberConfigDO.getValidate());
                registerDetail.setStatus(memberConfigDO.getFieldStatus());
                MemberConfigLabelUtil.removeOrUpdateIdByValue(registerDetail.getLabels(), items);
            });
            memberRegisterDetailRepository.saveAll(registerDetails);
        }

        MemberConfigQueryVO queryVO = new MemberConfigQueryVO();
        queryVO.setId(memberConfigDO.getId());
        queryVO.setFieldName(memberConfigDO.getFieldName());
        queryVO.setFieldLocalName(memberConfigDO.getFieldLocalName());
        queryVO.setFieldType(memberConfigDO.getFieldType());
        queryVO.setAttr(memberConfigDO.getAttr());
        queryVO.setFieldLength(memberConfigDO.getFieldLength());
        queryVO.setFieldEmpty(memberConfigDO.getFieldEmpty());
        queryVO.setFieldOrder(memberConfigDO.getFieldOrder());
        queryVO.setGroupName(memberConfigDO.getGroupName());
        queryVO.setFieldRemark(memberConfigDO.getFieldRemark());
        queryVO.setTagEnum(memberConfigDO.getTagEnum());
        queryVO.setFieldStatus(memberConfigDO.getFieldStatus());
        queryVO.setValidate(memberConfigDO.getValidate());
        queryVO.setFieldEnum(CollectionUtils.isEmpty(memberConfigDO.getLabels()) ? new ArrayList<>() : memberConfigDO.getLabels().stream().map(item -> {
            MemberConfigLabelQueryVO itemQueryVO = new MemberConfigLabelQueryVO();
            itemQueryVO.setId(item.getId());
            itemQueryVO.setLabel(item.getLabelValue());
            itemQueryVO.setOrder(item.getLabelOrder());
            return itemQueryVO;
        }).collect(Collectors.toList()));

        return Wrapper.success(queryVO);
    }

    /**
     * 分页查询注册资料配置
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberConfigQueryVO>> pageMemberConfig(PageVO pageVO) {
        // "id"是实体类的主键，记住一定要是实体类的属性，而不能是数据库的字段
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").ascending());
        Page<MemberConfigDO> result = memberConfigRepository.findAll(page);

        List<MemberConfigQueryVO> resultList = result.getContent().stream().map(r -> {
            MemberConfigQueryVO queryVO = new MemberConfigQueryVO();
            BeanUtils.copyProperties(r, queryVO);
            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(),resultList));
    }

    /**
     * 删除注册资料配置
     * @param configVO 接口参数
     * @return 删除结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> deleteMemberConfig(MemberConfigVO configVO) {
        MemberConfigDO configDO = memberConfigRepository.findById(configVO.getId()).orElse(null);
        if(configDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_DETAIL_DOES_NOT_EXIST);
        }

        //从角色关联中删除
        Specification<RoleDO> specification = (Specification<RoleDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            Join<RoleDO, MemberConfigDO> configJoin = root.join("configs", JoinType.LEFT);
            list.add(criteriaBuilder.equal(configJoin.get("id").as(Long.class), configDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<RoleDO> roleList = roleRepository.findAll(specification);
        if(!CollectionUtils.isEmpty(roleList)) {
            roleList.forEach(roleDO -> roleDO.getConfigs().removeIf(config -> config.getId().equals(configDO.getId())));
            roleRepository.saveAll(roleList);
        }

        //删除已经存在的会员注册资料
        memberRegisterDetailRepository.deleteByMemberConfig(configDO);

        //删除已经存在的入库资料
        memberDepositoryDetailRepository.deleteByMemberConfig(configDO);

        //删除当前实体（此操作删除当前实体）
        memberConfigRepository.delete(configDO);

        return Wrapper.success();
    }

    /**
     * 更新注册资料配置的状态
     * @param configVO 接口参数
     * @return 更新结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<MemberConfigQueryVO> updateMemberConfigStatus(MemberConfigVO configVO) {
        //检查会员资料配置是否存在
        MemberConfigDO memberConfigDO = memberConfigRepository.findById(configVO.getId()).orElse(null);
        if(memberConfigDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_DETAIL_DOES_NOT_EXIST);
        }

        memberConfigDO.setFieldStatus(configVO.getFieldStatus());
        memberConfigRepository.saveAndFlush(memberConfigDO);

        //更新已经存在的会员注册资料的状态
        List<MemberRegisterDetailDO> registerDetails = memberRegisterDetailRepository.findByMemberConfig(memberConfigDO);
        if(!CollectionUtils.isEmpty(registerDetails)) {
            registerDetails.forEach(registerDetail -> registerDetail.setStatus(memberConfigDO.getFieldStatus()));
            memberRegisterDetailRepository.saveAll(registerDetails);
        }

        MemberConfigQueryVO queryVO = new MemberConfigQueryVO();
        queryVO.setId(memberConfigDO.getId());
        queryVO.setFieldName(memberConfigDO.getFieldName());
        queryVO.setFieldLocalName(memberConfigDO.getFieldLocalName());
        queryVO.setFieldType(memberConfigDO.getFieldType());
        queryVO.setAttr(memberConfigDO.getAttr());
        queryVO.setFieldLength(memberConfigDO.getFieldLength());
        queryVO.setFieldEmpty(memberConfigDO.getFieldEmpty());
        queryVO.setFieldOrder(memberConfigDO.getFieldOrder());
        queryVO.setGroupName(memberConfigDO.getGroupName());
        queryVO.setFieldRemark(memberConfigDO.getFieldRemark());
        queryVO.setTagEnum(memberConfigDO.getTagEnum());
        queryVO.setFieldStatus(memberConfigDO.getFieldStatus());
        queryVO.setValidate(memberConfigDO.getValidate());
        queryVO.setFieldEnum(CollectionUtils.isEmpty(memberConfigDO.getLabels()) ? new ArrayList<>() : memberConfigDO.getLabels().stream().map(item -> {
            MemberConfigLabelQueryVO itemQueryVO = new MemberConfigLabelQueryVO();
            itemQueryVO.setId(item.getId());
            itemQueryVO.setLabel(item.getLabelValue());
            itemQueryVO.setOrder(item.getLabelOrder());
            return itemQueryVO;
        }).collect(Collectors.toList()));

        return Wrapper.success(queryVO);
    }

    /**
     * 新增或修改平台规则配置
     *
     * @param rules 平台规则
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> updateOrInsertMemberRules(List<MemberRuleFeignVO> rules) {
        List<BaseMemberRuleDO> memberRules = baseMemberRuleRepository.findAll();
        //修改状态
        memberRules.forEach(memberRule -> rules.stream().filter(rule -> rule.getRuleType().equals(memberRule.getRuleType()) && rule.getMethodCode().equals(memberRule.getMethodCode())).findFirst().ifPresent(rule -> memberRule.setStatus(rule.getStatus())));

        baseMemberRuleRepository.saveAll(memberRules);
        return Wrapper.success();
    }
}
